@isTest
private class CaseTeamHelperTest {

	private static final string ctRole_Billing = 'UnitTestBilling';
	private static final string ctRole_SS = 'Unit Tset Sales Support';
	
	private static final string Role_SS = 'Sales//Customer Support';
	private static final string Role_Billing = 'Billing';
	
	private static Map<string,User> testUsers = new Map<string, User>();
	private static Map<string,ID> natoRoleMap = null;
	private static ID natoProfileId = null;
	
	 
    static testMethod void testAddingTeamMember() {  
    	CreateCaseTeamRole(ctRole_Billing);
    	CreateCaseTeamRole(ctRole_SS);
    	  	
    	User u = CreateUser(Role_Billing);
    	
    	System.runAs(u){
	    	Case c = new Case();
	    	insert c;
	    		        
	    	// Add the user to the billing role of the case
	        Test.startTest();
	        CaseTeamHelper cth = new CaseTeamHelper();
	        cth.AddCaseTeamMember(u.ID, c.ID, ctRole_Billing, false);
	        cth.SaveToDatabase();
	        Test.stopTest();
	        
	        List<CaseTeamMember> teamMembers = [Select ID, ParentId, TeamRoleId, MemberId from CaseTeamMember where ParentId = :c.ID];
	        System.assert(teamMembers.size() == 1);
	        System.assert(teamMembers[0].MemberId == u.ID);
	        
	        List<CaseTeamRole> roles = [Select ID, Name from CaseTeamRole where ID = :teamMembers[0].TeamRoleId];        
	        System.assert(roles[0].Name == ctRole_Billing);
    	}
    }
    
    static testMethod void testRemovingTeamMember() {
    	CreateCaseTeamRole(ctRole_Billing);
    	CreateCaseTeamRole(ctRole_SS);

    	User u = CreateUser(Role_Billing);
    	User u2 = CreateUser(Role_SS);
    	
    	System.runAs(u){
	    	Case c = new Case();
	    	insert c;
	    	
	    	// Add user 1 to the billing role of the case, add user 2 to the Sales Support role
	        CaseTeamHelper cthPre = new CaseTeamHelper();
	        cthPre.AddCaseTeamMember(u.ID, c.ID, ctRole_Billing, false);
	        cthPre.AddCaseTeamMember(u2.ID, c.ID, ctRole_SS, false);
	        cthPre.SaveToDatabase();

			// Remove the user from the billing role	        
	        Test.startTest();
	        CaseTeamHelper cth = new CaseTeamHelper();
	        cth.RemoveAllUsersFromCaseTeamRole(c.ID, ctRole_Billing);
	        cth.SaveToDatabase();
	        Test.stopTest();
	        
	        List<CaseTeamMember> teamMembers = [Select ID, ParentId, TeamRoleId, MemberId from CaseTeamMember where ParentId = :c.ID];
	        System.assert(teamMembers.size() == 1);
	        System.assert(teamMembers[0].MemberId == u2.ID);
	        
	        List<CaseTeamRole> roles = [Select ID, Name from CaseTeamRole where ID = :teamMembers[0].TeamRoleId];        
	        System.assert(roles[0].Name == ctRole_SS);	               
    	}
    }

    static testMethod void testMultipleCases() {
    	CreateCaseTeamRole(ctRole_Billing);
    	CreateCaseTeamRole(ctRole_SS);

    	User u = CreateUser(Role_Billing);
    	User u2 = CreateUser(Role_SS);
    	
    	System.runAs(u){
	    	Case c1 = new Case();
	    	Case c2 = new Case();
	    	Case c3 = new Case();
    		List<Case> cases = new List<Case>{c1,c2,c3};
	    	insert cases;
			List<ID> caseIds = new List<ID>{c1.ID, c2.ID, c3.ID};
				    	
	    	// Case 1 has both users on the team (u1: billing / u2: SS)
	    	// Case 2 has one user (u1: billing) 
	    	// case 3 has one user (u2: ss)
	        CaseTeamHelper cthPre = new CaseTeamHelper();
	        cthPre.AddCaseTeamMember(u.ID, c1.ID, ctRole_Billing, false);
	        cthPre.AddCaseTeamMember(u2.ID, c1.ID, ctRole_SS, false);

	        cthPre.AddCaseTeamMember(u.ID, c2.ID, ctRole_Billing, false);

	        cthPre.AddCaseTeamMember(u2.ID, c3.ID, ctRole_SS, false);
	        cthPre.SaveToDatabase();
	        
	        Test.startTest();
	        CaseTeamHelper cth = new CaseTeamHelper();
	        	        
	        // Remove billing user from case2 and add u2 as the billing user
	        cth.AddCaseTeamMember(u2.ID, c2.ID, ctRole_Billing, true);

	        // Removing Billing and SS from case 3
	        cth.RemoveAllUsersFromCaseTeamRole(c3.ID, ctRole_Billing);
	        cth.RemoveAllUsersFromCaseTeamRole(c3.ID, ctRole_SS);
	        cth.SaveToDatabase();
	        Test.stopTest();
	        
	        Map<ID, CaseTeamRole> roles = new Map<ID, CaseTeamRole>([Select ID, Name from CaseTeamRole]);
	         
	        List<CaseTeamMember> teamMembers1 = [Select ID, ParentId, TeamRoleId, MemberId from CaseTeamMember where ParentId = :c1.ID];
	        System.assert(teamMembers1.size() == 2);
	        System.assert(roles.get(teamMembers1[0].TeamRoleId).Name == ctRole_SS || roles.get(teamMembers1[1].TeamRoleId).Name == ctRole_SS);
	        System.assert(roles.get(teamMembers1[0].TeamRoleId).Name == ctRole_Billing || roles.get(teamMembers1[1].TeamRoleId).Name == ctRole_Billing);
	        System.assert(teamMembers1[0].TeamRoleId != teamMembers1[1].TeamRoleId);
	        
	        List<CaseTeamMember> teamMembers2 = [Select ID, ParentId, TeamRoleId, MemberId from CaseTeamMember where ParentId = :c2.ID];
	        System.assert(teamMembers2.size() == 1);
	        System.assert(teamMembers2[0].MemberId == u2.ID);
	        System.assert(roles.get(teamMembers2[0].TeamRoleId).Name == ctRole_Billing);

	        List<CaseTeamMember> teamMembers3 = [Select ID, ParentId, TeamRoleId, MemberId from CaseTeamMember where ParentId = :c3.ID];
	        System.assert(teamMembers3.size() == 0);	        	        
    	}
    }

	private static void CreateCaseTeamRole(string caseTeamRoleName){
    	CaseTeamRole ctr = new CaseTeamRole();
    	ctr.Name = caseTeamRoleName;
    	ctr.PreferencesVisibleinCSP = true;
    	ctr.AccessLevel = 'Edit';
		insert ctr;		
	}
	
    private static User CreateUser(string role){
    	if(!testUsers.ContainsKey(role)){
    		
	    	if(null == natoProfileId)
				natoProfileId = [Select ID from Profile where Name = 'National Operations'][0].ID;
	 
	 		if(null == natoRoleMap){
	 			natoRoleMap = new Map<string, ID>();
	 			List<string> natoRolenames = new List<string> {Role_SS,Role_Billing};
				List<UserRole> roles = [Select ID, Name from UserRole where name in :natoRolenames];
				for(UserRole r: roles)
					natoRoleMap.put(r.Name, r.ID);
	 		}
	 		 
	 		ID roleID = natoRoleMap.get(role);
	 		string uniqueName = role.replace(' ', '_') + testUsers.size();
	 		
			User user = new User(alias = 'testUser', email='unitTest@attinteractive.com', 
	            emailencodingkey='UTF-8', lastname='Unit Test', languagelocalekey='en_US', 
	            localesidkey='en_US', profileid = natoProfileId, UserRoleId = roleID, 
	            timezonesidkey='America/Los_Angeles', AFrontier_Employee_ID__c= '12345' , username='unitTest@attinteractive.com.unitest.' + uniqueName);
	    
	    	insert user;
	    	testUsers.put(role, user);
    	}    	
		return testUsers.get(role);            
    }
    
}